package org.springblogs.batch.processor.stock;

import java.math.BigDecimal;
import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.springblogs.core.Status;
import org.springblogs.dao.StockInfoRepository;
import org.springblogs.dao.StockPriceRepository;
import org.springblogs.model.StockInfo;
import org.springblogs.model.StockPrice;
import org.springblogs.model.StockPriceId;
import org.springblogs.utils.HttpUtils;
import org.springblogs.utils.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Component
public class StockPriceItemProcessor extends AbstractBaseItemProcessor<StockInfo, StockPrice> {
	private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
	private static final long year = 31536000000L;
	// http://quotes.money.163.com/service/chddata.html?code=1300616&start=19901219&end=20180302&fields=TCLOSE;HIGH;LOW;TOPEN;LCLOSE;CHG;PCHG;VOTURNOVER;VATURNOVER
	private String format = "http://quotes.money.163.com/service/chddata.html?code=%s%s&start=%s&end=%s&fields=TCLOSE;HIGH;LOW;TOPEN;LCLOSE;CHG;PCHG;VOTURNOVER;VATURNOVER";
	@Autowired
	private StockInfoRepository stockInfoRepository;
	@Autowired
	private StockPriceRepository stockPriceRepository;

	@Transactional(propagation = Propagation.REQUIRES_NEW)
	@Override
	public StockPrice process(StockInfo item) throws Exception {
		if (item.getOnline() == 0) {
			return null;
		}
		try {
			// 更新 股票为 更新中
			item.setStatus(Status.UPDATING);
			stockInfoRepository.save(item);
			// 检查 股票价格 是否需要 更新
			if (needUpdate(item)) {
				// 如果上次执行成功，则从上次执行结束日期执行到今天
				if (Status.SUCCESS.equals(item.getStatus())) {
					item.setStartDate(item.getEndDate());
				}
				item.setEndDate(new Date());
				// 清除股票 更新数据
				stockPriceRepository.clearStockPriceByStockInfo(item);
				// 取 股票数据
				List<StockPrice> list = findStockPrice(item);
				// 保存股票 价格数据
				if (list.size() > 0) {
					stockPriceRepository.saveAll(list);
					stockPriceRepository.flush();
					log.info(String.format("stock %s in market %s from %s to %s saved %s datas.[%s]", item.getCode(), //
							item.getMarket(), //
							sdf.format(item.getStartDate()), sdf.format(item.getEndDate()), //
							list.size(), //
							item.getName()));
				}
				
				setOnline(item);
			}

			item.setStatus(Status.SUCCESS);
		} catch (Exception e) {
			item.setStatus(Status.FAIL);
		}
		// 更新 股票 更新成功/失败状态
		stockInfoRepository.save(item);
		return null;
	}

	private List<StockPrice> findStockPrice(StockInfo stock) throws ParseException {
		List<StockPrice> stockPrices = new ArrayList<>();
		Timestamp updatedDate = new Timestamp(System.currentTimeMillis());
		Date startDate = stock.getStartDate();
		Date endDate = stock.getEndDate();

		String code = stock.getCode();

		String url = String.format(format, //
				stock.getMarket().equals("sh") ? 0 : 1, // market
				code, // stock code
				sdf.format(startDate), // start query time
				sdf.format(endDate)// end query time
		);
		log.info(url);

		String str = HttpUtils.get(url, "gb2312", true);
		String[] ss = str.split("\n");
		log.debug(String.format("reponse stock %s from %s to %s has %s datas", code, sdf.format(startDate),
				sdf.format(endDate), ss.length - 1));
		// 每天的交易数据
		for (int i = 1; i < ss.length; i++) {
			String[] sp = ss[i].split(",");
			for (int j = 1; j < sp.length; j++) {
				if (sp[j].replaceAll("[0-9.+-]+", "").length() > 0) {
					sp[j] = "-1";
				}
			}
			StockPriceId id = new StockPriceId();
			id.setCode(code);
			id.setTradeDate(new Timestamp(sdf.parse(sp[0].replaceAll("[^0-9]", "")).getTime()));
			boolean existPrice = stockPriceRepository.existsById(id);
			if (log.isDebugEnabled()) {
				log.debug(String.format("check %s at %s %s have data", code, sdf.format(id.getTradeDate()), //
						existPrice ? StringUtils.EMPTY_STRING : "don't "));
			}
			if (!existPrice) {
				log.debug(String.format("create %s at %s stockprice", code, sdf.format(id.getTradeDate())));
				StockPrice stockPrice = new StockPrice();
				stockPrice.setCode(id.getCode());
				stockPrice.setTradeDate(id.getTradeDate());
				stockPrice.setName(stock.getName());
				stockPrice.setMarket(stock.getMarket());
				stockPrice.setUpdatedDate(updatedDate);

				stockPrice.setClosePrice(new BigDecimal(sp[3]));
				stockPrice.setMaxPrice(new BigDecimal(sp[4]));
				stockPrice.setMinPrice(new BigDecimal(sp[5]));
				stockPrice.setOpenPrice(new BigDecimal(sp[6]));

				stockPrice.setRise(new BigDecimal(sp[8]));
				stockPrice.setRiseRate(new BigDecimal(sp[9]));
				stockPrice.setVolume(new BigDecimal(sp[10]));
				stockPrice.setAmount(new BigDecimal(sp[11]));
				stockPrices.add(stockPrice);

				stock.setUpdatedDate(updatedDate);
			}
		}
		return stockPrices;
	}

	private boolean needUpdate(StockInfo item) {
		// 如果是开始日期与结束日期是  同一天， 则跳过
		boolean skip = !(item.getEndDate()!= null && item.getStartDate() != null && item.getStartDate().equals(item.getEndDate()));
		// 如果 股票 已经下线 则不需要更新
		skip |= item.getOnline() == 0;
		return skip;
	}
	// 0: offline, 1: online
	private void setOnline(StockInfo item) {
		if(item.getOnline() == 1) {
			Pageable page = PageRequest.of(0, 1, Direction.DESC, "tradeDate");
			StockPrice sp = new StockPrice();
			sp.setCode(item.getCode());
			Page<StockPrice> sps = stockPriceRepository.findAll(Example.of(sp), page);
			if(sps.getTotalElements() > 0) {
				sp = sps.stream().findFirst().get();
				Date tradeDate = sp.getTradeDate();
				long now = System.currentTimeMillis();
				if(now - tradeDate.getTime() > year) {
					item.setOnline(0);
				}
			}
		}
	}
}
